package LuMin.dict_service.tcp;

/**
 * @author lumin
 * @date 2022/05/14 11:35
 **/
import java.io.*;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.HashMap;
import java.util.Scanner;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

// UDP: 无连接       写信
// TCP: 有连接       打电话
public class 支持多个客户端同时处理的长连接Server {
    private static final HashMap<String, String> map = new HashMap<>();
    static {
        map.put("apple", "苹果");
        map.put("banana", "香蕉");
    }

    private static class ServerTask implements Runnable {
        private final Socket socket;

        private ServerTask(Socket socket) {
            this.socket = socket;
        }

        @Override
        public void run() {
            try {
                InetAddress inetAddress = socket.getInetAddress();
                Log.println("对方的地址: " + inetAddress);
                int port = socket.getPort();
                Log.println("对方的端口: " + port);

                // is: 用于读数据
                InputStream is = socket.getInputStream();
                Scanner scanner = new Scanner(is, "UTF-8");
                // os: 用于写数据
                OutputStream os = socket.getOutputStream();
                // OutputStream -> OutputStreamWriter -> PrintWriter
                OutputStreamWriter writer = new OutputStreamWriter(os, "UTF-8");
                PrintWriter printWriter = new PrintWriter(writer);

                // client 挂断电话，表示本次连接的请求响应处理结束了
                // client 通过关闭连接的方式来体现
                // is 读到了 EOS(-1)
                // scanner hasNextLine()
                while (scanner.hasNextLine()) {
                    // 2. 读取请求
                    String header = scanner.nextLine(); // "我是 Java19班的"    // 阻塞
                    // TODO: 做请求格式检查
                    String englishWord = scanner.nextLine();
                    Log.println("英文单词: " + englishWord);

                    // 3. 处理业务
                    String chineseWord = map.getOrDefault(englishWord, "不认识");
                    Log.println("中文单词: " + chineseWord);

                    // 4. 发送响应
                    // 好的\r\n苹果\r\n

                    Log.println("服务器进行发送");
                    printWriter.printf("好的\r\n%s\r\n", chineseWord);
                    printWriter.flush();    // 不要忘记 flush
                    Log.println("服务器发送成功");
                }

                socket.close();
            } catch (IOException exc) {
                exc.printStackTrace();
            }
        }
    }

    public static void main(String[] args) throws IOException {
        // 直接使用线程池，直接使用 Java 中预先定义好的线程池（Executors）
        ExecutorService service = Executors.newFixedThreadPool(10);
        // 给线程池提交任务(Runnable 体现：
        // accept 主线程
        // 剩下的工作，交给线程中的线程去执行

        // 1. 开店（创建 socket）
        Log.println("服务器启动，监听在 TCP:8080 端口");
        ServerSocket serverSocket = new ServerSocket(8080);
        // 进行循环
        while (true) {
            // 1. 接通连接（电话） —— accept
            Log.println("等待新的客户端连接上来");
            Socket socket = serverSocket.accept();  // 阻塞
            Log.println("有新的客户端连接上来");

            ServerTask task = new ServerTask(socket);     // 封装好让线程池处理的任务对象
            service.execute(task);
        }
    }
}